#!/usr/bin/env python3
"""
全面的过滤器测试套件
包含所有过滤器功能、图表类型、x/y轴配置、分段等所有配置的测试
至少200个测试用例
"""

import json
import time
import requests
from datetime import datetime, timedelta
import random
from typing import Dict, List, Any


class ComprehensiveFilterTest:
    def __init__(self):
        self.base_url = "http://localhost:5000"
        self.test_cases = []
        self.results = []
        
        # 定义所有配置选项
        self.chart_types = ["bar", "line", "pie", "doughnut", "polarArea", "radar"]
        
        self.all_fields = [
            "index", "trade_id", "symbol", "direction", "side", "trade_type", 
            "session", "nth_trade", "open_price", "close_price", "open_qty", 
            "close_qty", "open_datetime", "close_datetime", "holding_time", 
            "open_order_type", "close_order_type", "net_profit", "gross_profit", 
            "commission", "point_profit_per_lot", "total_points", 
            "max_floating_profit_points", "max_floating_profit_dollars", 
            "max_floating_loss_points", "max_floating_loss_dollars", 
            "entry_reason", "exit_reason", "stop_loss_price", "stop_loss_reason", 
            "take_profit_price", "take_profit_reason", "rating", "evaluation", 
            "open_rrr", "close_rrr", "fwr", "mood", "notes"
        ]
        
        self.numeric_fields = [
            "index", "nth_trade", "open_price", "close_price", "open_qty", 
            "close_qty", "point_profit_per_lot", "total_points", "gross_profit", 
            "net_profit", "commission", "max_floating_profit_points", 
            "max_floating_profit_dollars", "max_floating_loss_points", 
            "max_floating_loss_dollars", "stop_loss_price", "take_profit_price", 
            "rating", "open_rrr", "close_rrr", "fwr"
        ]
        
        self.string_fields = [
            "trade_id", "symbol", "direction", "side", "trade_type", "session", 
            "open_order_type", "close_order_type", "entry_reason", "exit_reason", 
            "stop_loss_reason", "take_profit_reason", "evaluation", "mood", "notes"
        ]
        
        self.datetime_fields = ["open_datetime", "close_datetime"]
        
        self.operators = [
            "equals", "not_equals", "contains", "not_contains", "greater_than", 
            "less_than", "greater_than_or_equal", "less_than_or_equal", 
            "is_null", "is_not_null", "is_empty", "is_not_empty"
        ]
        
        self.aggregations = ["sum", "avg", "max", "min", "count", "median", "stddev"]
        
        self.y_fields = [
            "count", "win_rate", "profit_factor", "average_win", "average_loss",
            "net_profit", "gross_profit", "commission", "point_profit_per_lot",
            "total_points", "max_floating_profit_points", "max_floating_profit_dollars",
            "max_floating_loss_points", "max_floating_loss_dollars", "rating",
            "open_rrr", "close_rrr", "fwr"
        ]
        
        self.sort_options = ["label_asc", "label_desc", "value_asc", "value_desc", "count_desc"]
        
        self.binning_methods = ["fixed_size", "fixed_count", "percentile", "auto"]
        
        self.binning_formats = ["range", "center", "lower", "upper"]
        
        self.color_schemes = ["profit_loss", "performance", "rainbow", "monochrome"]
        
        self.value_formats = ["currency", "percentage", "decimal", "integer"]
        
        # 预设值
        self.preset_values = {
            "symbol": ["MESM25", "MESU25", "MNQM25", "AAPL", "TSLA", "MSFT", "GOOGL"],
            "direction": ["Long", "Short"],
            "side": ["Left", "Right", "Mid"],
            "trade_type": ["Scalp", "Swing", "Position", "Intraday", "mr", "target"],
            "session": ["RTH", "ETH"],
            "entry_reason": ["赌突破", "赌反转", "breakout", "DBDT", "s&r", "wedge top"],
            "exit_reason": ["达到目标位", "达到止损位", "符合预期-盈利离场", "不符合预期-亏损离场"],
            "evaluation": ["优秀", "良好", "一般", "差"],
            "mood": ["开心", "沮丧", "平静", "兴奋", "紧张"]
        }
        
    def generate_single_filter_tests(self):
        """生成单个过滤器测试"""
        print("生成单个过滤器测试...")
        
        # 为每个字段类型和操作符生成测试
        for field in self.all_fields:
            for operator in self.operators:
                # 跳过不兼容的组合
                if field in self.numeric_fields and operator in ["contains", "not_contains"]:
                    continue
                if field in self.string_fields and operator in ["greater_than", "less_than", "greater_than_or_equal", "less_than_or_equal"]:
                    continue
                
                test_case = self.create_filter_test_case(
                    name=f"单过滤器_{field}_{operator}",
                    field=field,
                    operator=operator,
                    chart_type=random.choice(self.chart_types),
                    x_field=random.choice(self.all_fields),
                    y_field=random.choice(self.y_fields)
                )
                
                self.test_cases.append(test_case)
    
    def generate_chart_type_tests(self):
        """生成图表类型测试"""
        print("生成图表类型测试...")
        
        for chart_type in self.chart_types:
            for x_field in random.sample(self.all_fields, 5):  # 每种图表类型测试5个x字段
                for y_field in random.sample(self.y_fields, 3):  # 每个x字段测试3个y字段
                    test_case = self.create_chart_config_test_case(
                        name=f"图表类型_{chart_type}_{x_field}_{y_field}",
                        chart_type=chart_type,
                        x_field=x_field,
                        y_field=y_field
                    )
                    
                    self.test_cases.append(test_case)
    
    def generate_aggregation_tests(self):
        """生成聚合方式测试"""
        print("生成聚合方式测试...")
        
        for aggregation in self.aggregations:
            for field in random.sample(self.numeric_fields, 5):
                test_case = self.create_aggregation_test_case(
                    name=f"聚合_{aggregation}_{field}",
                    aggregation=aggregation,
                    field=field
                )
                
                self.test_cases.append(test_case)
    
    def generate_binning_tests(self):
        """生成分段配置测试"""
        print("生成分段配置测试...")
        
        for method in self.binning_methods:
            for format_type in self.binning_formats:
                for field in random.sample(self.numeric_fields, 3):
                    test_case = self.create_binning_test_case(
                        name=f"分段_{method}_{format_type}_{field}",
                        method=method,
                        format_type=format_type,
                        field=field
                    )
                    
                    self.test_cases.append(test_case)
    
    def generate_sorting_tests(self):
        """生成排序配置测试"""
        print("生成排序配置测试...")
        
        for sort_option in self.sort_options:
            for field in random.sample(self.all_fields, 3):
                test_case = self.create_sorting_test_case(
                    name=f"排序_{sort_option}_{field}",
                    sort_option=sort_option,
                    field=field
                )
                
                self.test_cases.append(test_case)
    
    def generate_multi_filter_tests(self):
        """生成多过滤器组合测试"""
        print("生成多过滤器组合测试...")
        
        # 生成各种复杂的过滤器组合
        for logic in ["and", "or"]:
            for combo_size in [2, 3, 4, 5]:
                for _ in range(5):  # 每个组合大小生成5个测试
                    test_case = self.create_multi_filter_test_case(
                        name=f"多过滤器_{logic}_{combo_size}个条件",
                        logic=logic,
                        combo_size=combo_size
                    )
                    
                    self.test_cases.append(test_case)
    
    def generate_advanced_config_tests(self):
        """生成高级配置测试"""
        print("生成高级配置测试...")
        
        # 颜色方案测试
        for color_scheme in self.color_schemes:
            test_case = self.create_advanced_config_test_case(
                name=f"颜色方案_{color_scheme}",
                color_scheme=color_scheme
            )
            self.test_cases.append(test_case)
        
        # 数值格式测试
        for value_format in self.value_formats:
            test_case = self.create_advanced_config_test_case(
                name=f"数值格式_{value_format}",
                value_format=value_format
            )
            self.test_cases.append(test_case)
        
        # 最大显示数量测试
        for max_items in [10, 20, 50, -1]:
            test_case = self.create_advanced_config_test_case(
                name=f"最大显示_{max_items}",
                max_items=max_items
            )
            self.test_cases.append(test_case)
    
    def generate_edge_case_tests(self):
        """生成边界情况测试"""
        print("生成边界情况测试...")
        
        # 空值测试
        for field in random.sample(self.all_fields, 10):
            test_case = self.create_edge_case_test_case(
                name=f"空值测试_{field}",
                case_type="null_test",
                field=field
            )
            self.test_cases.append(test_case)
        
        # 极值测试
        for field in self.numeric_fields:
            test_case = self.create_edge_case_test_case(
                name=f"极值测试_{field}",
                case_type="extreme_value",
                field=field
            )
            self.test_cases.append(test_case)
        
        # 特殊字符测试
        for field in self.string_fields:
            test_case = self.create_edge_case_test_case(
                name=f"特殊字符测试_{field}",
                case_type="special_chars",
                field=field
            )
            self.test_cases.append(test_case)
    
    def create_filter_test_case(self, name: str, field: str, operator: str, chart_type: str, x_field: str, y_field: str) -> Dict:
        """创建过滤器测试用例"""
        value = self.get_test_value(field, operator)
        
        config = {
            "name": name,
            "chart_type": chart_type,
            "x_field": x_field,
            "y_field": y_field,
            "x_aggregation": "count",
            "y_aggregation": random.choice(self.aggregations),
            "filters": [
                {
                    "field": field,
                    "operator": operator,
                    "value": value,
                    "logic": "and"
                }
            ],
            "x_sort": random.choice(self.sort_options),
            "x_max_items": random.choice([10, 20, 50, -1]),
            "x_include_empty": random.choice([True, False]),
            "expected_result": {
                "type": "filter_test",
                "should_have_data": operator not in ["is_null", "is_empty"]
            }
        }
        
        return config
    
    def create_chart_config_test_case(self, name: str, chart_type: str, x_field: str, y_field: str) -> Dict:
        """创建图表配置测试用例"""
        config = {
            "name": name,
            "chart_type": chart_type,
            "x_field": x_field,
            "y_field": y_field,
            "x_aggregation": "count",
            "y_aggregation": random.choice(self.aggregations),
            "filters": [],
            "x_sort": random.choice(self.sort_options),
            "x_max_items": random.choice([10, 20, 50, -1]),
            "x_include_empty": True,
            "color_scheme": random.choice(self.color_schemes),
            "value_format": random.choice(self.value_formats),
            "expected_result": {
                "type": "chart_config_test",
                "chart_type": chart_type,
                "should_have_data": True
            }
        }
        
        return config
    
    def create_aggregation_test_case(self, name: str, aggregation: str, field: str) -> Dict:
        """创建聚合测试用例"""
        config = {
            "name": name,
            "chart_type": "bar",
            "x_field": "symbol",
            "y_field": field,
            "x_aggregation": "count",
            "y_aggregation": aggregation,
            "filters": [],
            "x_sort": "value_desc",
            "x_max_items": 10,
            "x_include_empty": True,
            "expected_result": {
                "type": "aggregation_test",
                "aggregation": aggregation,
                "should_have_data": True
            }
        }
        
        return config
    
    def create_binning_test_case(self, name: str, method: str, format_type: str, field: str) -> Dict:
        """创建分段测试用例"""
        binning_values = {
            "fixed_size": 100,
            "fixed_count": 10,
            "percentile": 20,
            "auto": 15
        }
        
        config = {
            "name": name,
            "chart_type": "bar",
            "x_field": field,
            "y_field": "count",
            "x_aggregation": "count",
            "y_aggregation": "count",
            "filters": [],
            "x_sort": "label_asc",
            "x_max_items": -1,
            "x_include_empty": True,
            "x_enable_binning": True,
            "x_binning_method": method,
            "x_binning_value": binning_values[method],
            "x_binning_format": format_type,
            "x_binning_include_empty": False,
            "x_binning_round_values": True,
            "expected_result": {
                "type": "binning_test",
                "method": method,
                "format": format_type,
                "should_have_data": True
            }
        }
        
        return config
    
    def create_sorting_test_case(self, name: str, sort_option: str, field: str) -> Dict:
        """创建排序测试用例"""
        config = {
            "name": name,
            "chart_type": "bar",
            "x_field": field,
            "y_field": "count",
            "x_aggregation": "count",
            "y_aggregation": "count",
            "filters": [],
            "x_sort": sort_option,
            "x_max_items": 20,
            "x_include_empty": True,
            "expected_result": {
                "type": "sorting_test",
                "sort_option": sort_option,
                "should_have_data": True
            }
        }
        
        return config
    
    def create_multi_filter_test_case(self, name: str, logic: str, combo_size: int) -> Dict:
        """创建多过滤器测试用例"""
        filters = []
        
        for i in range(combo_size):
            field = random.choice(self.all_fields)
            operator = self.get_compatible_operator(field)
            value = self.get_test_value(field, operator)
            
            filter_item = {
                "field": field,
                "operator": operator,
                "value": value,
                "logic": logic if i < combo_size - 1 else "and"
            }
            
            filters.append(filter_item)
        
        config = {
            "name": name,
            "chart_type": random.choice(self.chart_types),
            "x_field": random.choice(self.all_fields),
            "y_field": random.choice(self.y_fields),
            "x_aggregation": "count",
            "y_aggregation": random.choice(self.aggregations),
            "filters": filters,
            "x_sort": random.choice(self.sort_options),
            "x_max_items": random.choice([10, 20, 50, -1]),
            "x_include_empty": random.choice([True, False]),
            "expected_result": {
                "type": "multi_filter_test",
                "logic": logic,
                "filter_count": combo_size,
                "should_have_data": True
            }
        }
        
        return config
    
    def create_advanced_config_test_case(self, name: str, **kwargs) -> Dict:
        """创建高级配置测试用例"""
        config = {
            "name": name,
            "chart_type": "bar",
            "x_field": "symbol",
            "y_field": "net_profit",
            "x_aggregation": "count",
            "y_aggregation": "sum",
            "filters": [],
            "x_sort": "value_desc",
            "x_max_items": kwargs.get("max_items", 20),
            "x_include_empty": True,
            "color_scheme": kwargs.get("color_scheme", "profit_loss"),
            "value_format": kwargs.get("value_format", "decimal"),
            "expected_result": {
                "type": "advanced_config_test",
                "should_have_data": True
            }
        }
        
        return config
    
    def create_edge_case_test_case(self, name: str, case_type: str, field: str) -> Dict:
        """创建边界情况测试用例"""
        config = {
            "name": name,
            "chart_type": "bar",
            "x_field": field,
            "y_field": "count",
            "x_aggregation": "count",
            "y_aggregation": "count",
            "filters": [],
            "x_sort": "value_desc",
            "x_max_items": 10,
            "x_include_empty": True,
            "expected_result": {
                "type": "edge_case_test",
                "case_type": case_type,
                "should_have_data": True
            }
        }
        
        if case_type == "null_test":
            config["filters"] = [
                {
                    "field": field,
                    "operator": "is_null",
                    "value": "",
                    "logic": "and"
                }
            ]
        elif case_type == "extreme_value":
            config["filters"] = [
                {
                    "field": field,
                    "operator": "greater_than",
                    "value": 999999,
                    "logic": "and"
                }
            ]
        elif case_type == "special_chars":
            config["filters"] = [
                {
                    "field": field,
                    "operator": "contains",
                    "value": "!@#$%^&*()",
                    "logic": "and"
                }
            ]
        
        return config
    
    def get_compatible_operator(self, field: str) -> str:
        """获取与字段类型兼容的操作符"""
        if field in self.numeric_fields:
            return random.choice(["equals", "not_equals", "greater_than", "less_than", 
                                "greater_than_or_equal", "less_than_or_equal", "is_null", "is_not_null"])
        elif field in self.string_fields:
            return random.choice(["equals", "not_equals", "contains", "not_contains", 
                                "is_null", "is_not_null", "is_empty", "is_not_empty"])
        else:
            return random.choice(["equals", "not_equals", "is_null", "is_not_null"])
    
    def get_test_value(self, field: str, operator: str):
        """获取测试值"""
        if operator in ["is_null", "is_not_null", "is_empty", "is_not_empty"]:
            return ""
        
        if field in self.preset_values:
            return random.choice(self.preset_values[field])
        
        if field in self.numeric_fields:
            if operator in ["greater_than", "less_than", "greater_than_or_equal", "less_than_or_equal"]:
                return random.randint(-1000, 1000)
            else:
                return random.randint(0, 100)
        
        if field in self.string_fields:
            test_strings = ["test", "example", "sample", "data", "value"]
            return random.choice(test_strings)
        
        return "test_value"
    
    def run_test_case(self, test_case: Dict) -> Dict:
        """运行单个测试用例"""
        try:
            # 构建请求数据
            request_data = {
                "config": json.dumps(test_case)
            }
            
            # 发送GET请求，配置作为URL参数
            response = requests.get(
                f"{self.base_url}/statistics/chart_data",
                params=request_data,
                timeout=30
            )
            
            # 检查响应
            if response.status_code == 200:
                result_data = response.json()
                
                # 验证结果
                validation_result = self.validate_result(test_case, result_data)
                
                return {
                    "test_case": test_case["name"],
                    "status": "PASS" if validation_result["valid"] else "FAIL",
                    "response_time": response.elapsed.total_seconds(),
                    "data_count": len(result_data.get("data", [])),
                    "validation": validation_result,
                    "details": {
                        "chart_type": test_case["chart_type"],
                        "x_field": test_case["x_field"],
                        "y_field": test_case["y_field"],
                        "filter_count": len(test_case["filters"]),
                        "response_size": len(json.dumps(result_data))
                    }
                }
            else:
                return {
                    "test_case": test_case["name"],
                    "status": "ERROR",
                    "error": f"HTTP {response.status_code}: {response.text[:200]}",
                    "response_time": response.elapsed.total_seconds(),
                    "data_count": 0,
                    "validation": {"valid": False, "message": "HTTP error"},
                    "details": test_case
                }
        
        except Exception as e:
            return {
                "test_case": test_case["name"],
                "status": "ERROR",
                "error": str(e)[:200],
                "response_time": 0,
                "data_count": 0,
                "validation": {"valid": False, "message": f"Exception: {str(e)[:100]}"},
                "details": test_case
            }
    
    def validate_result(self, test_case: Dict, result_data: Dict) -> Dict:
        """验证测试结果"""
        expected = test_case["expected_result"]
        
        # 基础验证
        if "data" not in result_data:
            return {"valid": False, "message": "结果中没有data字段"}
        
        # 检查数据是否为空
        has_data = len(result_data["data"]) > 0
        
        if expected["should_have_data"] and not has_data:
            return {"valid": False, "message": "期望有数据但实际为空"}
        
        # 检查图表类型
        if expected["type"] == "chart_config_test":
            if "chart_type" not in result_data:
                return {"valid": False, "message": "结果中没有chart_type字段"}
            
            if result_data["chart_type"] != expected["chart_type"]:
                return {"valid": False, "message": f"图表类型不匹配: 期望{expected['chart_type']}, 实际{result_data['chart_type']}"}
        
        # 检查过滤器结果
        if expected["type"] == "filter_test":
            # 可以添加更多过滤器特定的验证
            pass
        
        # 检查聚合结果
        if expected["type"] == "aggregation_test":
            if has_data and "data" in result_data:
                # 验证聚合结果是否合理
                data_values = [item.get("value", 0) for item in result_data["data"]]
                if expected["aggregation"] == "sum" and any(v < 0 for v in data_values):
                    # 对于sum聚合，可能有负值，这是正常的
                    pass
        
        return {"valid": True, "message": "验证通过"}
    
    def run_all_tests(self):
        """运行所有测试"""
        print(f"开始运行 {len(self.test_cases)} 个测试用例...")
        
        start_time = time.time()
        
        for i, test_case in enumerate(self.test_cases):
            print(f"运行测试 {i+1}/{len(self.test_cases)}: {test_case['name']}")
            
            result = self.run_test_case(test_case)
            self.results.append(result)
            
            # 短暂延迟，避免过度请求
            time.sleep(0.1)
        
        end_time = time.time()
        
        # 生成报告
        self.generate_report(end_time - start_time)
    
    def generate_report(self, total_time: float):
        """生成测试报告"""
        print(f"\n{'='*50}")
        print("测试报告")
        print(f"{'='*50}")
        
        total_tests = len(self.results)
        passed_tests = sum(1 for r in self.results if r["status"] == "PASS")
        failed_tests = sum(1 for r in self.results if r["status"] == "FAIL")
        error_tests = sum(1 for r in self.results if r["status"] == "ERROR")
        
        print(f"总测试数: {total_tests}")
        print(f"通过: {passed_tests} ({passed_tests/total_tests*100:.1f}%)")
        print(f"失败: {failed_tests} ({failed_tests/total_tests*100:.1f}%)")
        print(f"错误: {error_tests} ({error_tests/total_tests*100:.1f}%)")
        print(f"总耗时: {total_time:.2f}秒")
        print(f"平均响应时间: {sum(r['response_time'] for r in self.results)/total_tests:.3f}秒")
        
        # 按测试类型统计
        test_types = {}
        for result in self.results:
            test_name = result["test_case"]
            test_type = test_name.split("_")[0]
            if test_type not in test_types:
                test_types[test_type] = {"total": 0, "passed": 0, "failed": 0, "error": 0}
            
            test_types[test_type]["total"] += 1
            if result["status"] == "PASS":
                test_types[test_type]["passed"] += 1
            elif result["status"] == "FAIL":
                test_types[test_type]["failed"] += 1
            else:
                test_types[test_type]["error"] += 1
        
        print(f"\n按测试类型统计:")
        for test_type, stats in test_types.items():
            print(f"  {test_type}: {stats['passed']}/{stats['total']} 通过 ({stats['passed']/stats['total']*100:.1f}%)")
        
        # 显示失败和错误的测试
        if failed_tests > 0:
            print(f"\n失败的测试:")
            for result in self.results:
                if result["status"] == "FAIL":
                    print(f"  - {result['test_case']}: {result['validation']['message']}")
        
        if error_tests > 0:
            print(f"\n错误的测试:")
            for result in self.results:
                if result["status"] == "ERROR":
                    print(f"  - {result['test_case']}: {result['error']}")
        
        # 性能统计
        response_times = [r["response_time"] for r in self.results if r["response_time"] > 0]
        if response_times:
            print(f"\n性能统计:")
            print(f"  最快响应: {min(response_times):.3f}秒")
            print(f"  最慢响应: {max(response_times):.3f}秒")
            print(f"  平均响应: {sum(response_times)/len(response_times):.3f}秒")
        
        # 保存详细报告
        self.save_detailed_report()
    
    def save_detailed_report(self):
        """保存详细测试报告"""
        report_data = {
            "timestamp": datetime.now().isoformat(),
            "summary": {
                "total_tests": len(self.results),
                "passed": sum(1 for r in self.results if r["status"] == "PASS"),
                "failed": sum(1 for r in self.results if r["status"] == "FAIL"),
                "errors": sum(1 for r in self.results if r["status"] == "ERROR")
            },
            "test_cases": self.test_cases,
            "results": self.results
        }
        
        with open("comprehensive_filter_test_report.json", "w", encoding="utf-8") as f:
            json.dump(report_data, f, ensure_ascii=False, indent=2)
        
        print(f"\n详细报告已保存到: comprehensive_filter_test_report.json")
    
    def generate_all_test_cases(self):
        """生成所有测试用例"""
        print("开始生成全面的测试用例...")
        
        # 生成各种类型的测试
        self.generate_single_filter_tests()
        self.generate_chart_type_tests()
        self.generate_aggregation_tests()
        self.generate_binning_tests()
        self.generate_sorting_tests()
        self.generate_multi_filter_tests()
        self.generate_advanced_config_tests()
        self.generate_edge_case_tests()
        
        print(f"总共生成了 {len(self.test_cases)} 个测试用例")
        
        # 保存测试用例
        with open("comprehensive_test_cases.json", "w", encoding="utf-8") as f:
            json.dump(self.test_cases, f, ensure_ascii=False, indent=2)
        
        print("测试用例已保存到: comprehensive_test_cases.json")


def main():
    """主函数"""
    print("启动全面的过滤器测试套件...")
    
    tester = ComprehensiveFilterTest()
    
    # 生成测试用例
    tester.generate_all_test_cases()
    
    # 运行测试
    tester.run_all_tests()
    
    print("\n全面测试完成!")


if __name__ == "__main__":
    main() 